package cn.sangedon.review.analysis.service.impl;

import cn.sangedon.review.analysis.config.AnalysisConfig;
import cn.sangedon.review.analysis.constant.RedisEnum;
import cn.sangedon.review.analysis.constant.StasticOrderType;
import cn.sangedon.review.analysis.domain.StasticsQuery;
import cn.sangedon.review.analysis.mapper.StockStasticsMapper;
import cn.sangedon.review.analysis.service.RedisServer;
import cn.sangedon.review.analysis.service.StockStasticsService;
import cn.sangedon.review.analysis.stastics.specific.MarketTrendStastics;
import cn.sangedon.review.analysis.utils.CheckUtil;
import cn.sangedon.review.common.constant.MarketType;
import cn.sangedon.review.common.constant.TypeConstant;
import cn.sangedon.review.common.domain.analysis.StockStastics;
import cn.sangedon.review.common.domain.analysis.StockStrategyResult;
import cn.sangedon.review.common.domain.analysis.TrendStastics;
import cn.sangedon.review.common.domain.data.SnowballQuotation;
import cn.sangedon.review.common.domain.data.StockDayInfo;
import cn.sangedon.review.common.service.data.SnowballQuotationService;
import cn.sangedon.review.common.service.data.StockDayInfoService;
import cn.sangedon.review.common.service.data.TradingDateService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

/**
 * @author dongliangqiong
 * @description 针对表【tb_stock_stastics(股票统计信息表)】的数据库操作Service实现
 * @createDate 2022-09-22 14:03:25
 */
@Slf4j
@Service
public class StockStasticsServiceImpl extends ServiceImpl<StockStasticsMapper, StockStastics> implements StockStasticsService {
    @Autowired
    private MarketTrendStastics marketTrendStastics;

    @DubboReference
    private StockDayInfoService stockDayInfoService;

    @DubboReference
    private SnowballQuotationService snowballQuotationService;

    @Autowired
    private TradingDateService tradingDateService;

    @Autowired
    private RedisServer redisServer;

    @Autowired
    private AnalysisConfig analysisConfig;

    @Override
    public String getStasticsDate() {
        return this.baseMapper.getStasticsDate();
    }

    @Override
    public List<StockStastics> listOrderByType(StasticsQuery stasticsQuery) {
        QueryWrapper<StockStastics> query = new QueryWrapper<>();
        if (StasticOrderType.RISE.equals(stasticsQuery.getOrderType())) {
            query.orderByDesc("rise_day");
        } else if (StasticOrderType.DROP.equals(stasticsQuery.getOrderType())) {
            query.orderByDesc("fall_day");
        } else if (StasticOrderType.ENLARGE.equals(stasticsQuery.getOrderType())) {
            query.orderByDesc("enlarge_volume_day");
        } else if (StasticOrderType.REDUCE.equals(stasticsQuery.getOrderType())) {
            query.orderByDesc("reduce_volume_day");
        } else {
            query.orderByDesc("rise_day");
        }

        if (stasticsQuery.getPageNo() != null && stasticsQuery.getPageSize() != null) {
            query.last(" limit " + (stasticsQuery.getPageNo() - 1) * stasticsQuery.getPageSize() + ", " + stasticsQuery.getPageSize());
        }

        return this.list(query);
    }

    @Override
    public List<TrendStastics> trend(Integer cycleDays) {
        String latestDate = stockDayInfoService.getLatestDate();
        List<TrendStastics> trendStastics = marketTrendStastics.trendStastics(latestDate, cycleDays);
        trendStastics = trendStastics.stream().sorted((e1, e2) -> e2.getChangeRate().compareTo(e1.getChangeRate()))
                                     .collect(Collectors.toList());
        return trendStastics;
    }

    @Override
    public List<StockStrategyResult> suggestFallShrinkRedIntime() {
        //        if (!tradingDateService.isTradingHours(null)) {
        //            log.info("非交易时间段，获取最新缓存数据");
        //            String quotationIntimeStr = (String) redisServer.get(RedisEnum.QUATATION_INTIME.getKey());
        //            return JSONObject.parseArray(quotationIntimeStr, StockStrategyResult.class);
        //        }
        String latestDate = stockDayInfoService.getLatestDate();
        log.info("开始获取实时下跌缩量红策略结果，最新股票日交易数据交易日：{}", latestDate);
        List<StockDayInfo> stockDayInfos = stockDayInfoService.getStockDayInfos(latestDate, TypeConstant.EQ);
        List<SnowballQuotation> snowballQuotations = snowballQuotationService.listLatest();
        if (CollectionUtils.isEmpty(snowballQuotations)) {
            log.info("未获取到最新的实时数据");
            return Collections.emptyList();
        }

        List<StockStastics> list = this.continuousFall(2);
        Map<String, StockStastics> stasticsMap = list.stream().collect(Collectors.toMap(StockStastics::getStockCode, Function.identity()));
        log.info("最新实时数据：{}", snowballQuotations.get(0).getTradingDate());
        List<StockStrategyResult> results = new ArrayList<>();
        Map<String, StockDayInfo> dayInfoMap = stockDayInfos.stream().collect(Collectors.toMap(StockDayInfo::getCode, Function.identity()));
        snowballQuotations.forEach(e -> {
            StockDayInfo yestoday = dayInfoMap.get(e.getCode());
            if (stasticsMap.get(e.getCode()) == null || yestoday == null ||
                !(e.getCode().startsWith(MarketType.SHZB.getPrefix()) || e.getCode().startsWith(MarketType.SZZB.getPrefix()))) {
                return;
            }
            if (CheckUtil.fallShrinkRed(e, yestoday)) {
                StockStrategyResult strategyResult = new StockStrategyResult();
                strategyResult.setStrategyName("下跌缩量红实时");
                strategyResult.setStockCode(yestoday.getCode());
                strategyResult.setStockName(e.getName());
                strategyResult.setTradingDate(e.getGmtCreate());
                results.add(strategyResult);
            }
        });

        redisServer.save(RedisEnum.QUATATION_INTIME.getKey(), results);
        log.info("实时下跌缩量红策略运行成功, 策略选股数量:{}", results.size());
        try {
            FileWriter writer = new FileWriter(analysisConfig.getDataDir() + "real-time-fall-shrink-red.csv");
            String collect = results.stream().map(StockStrategyResult::getStockCode).collect(Collectors.joining(","));
            writer.write(collect);
            writer.flush();
        } catch (Exception e) {
            log.info("写入csv出错:{}", e);
        }

        return results;
    }

    @Override
    public List<StockStastics> continuousShrinkRise() {
        return this.baseMapper.continuousShrinkRise();
    }

    @Override
    public List<StockStastics> listLatest() {
        return this.baseMapper.listLatest();
    }

    @Override
    public List<StockStastics> continuousHignVolumeRise() {
        return this.baseMapper.continuousHignVolumeRise();
    }

    @Override
    public List<StockStrategyResult> fallShrinkRed(String preTradeDate, String tradeDate) {
        return this.baseMapper.fallShrinkRed(preTradeDate, tradeDate);
    }

    private List<StockStastics> continuousFall(int fallDays) {
        return this.baseMapper.continuousFall(fallDays);
    }
}




